package cn.edu.my.regression.linear.unary;

import java.math.BigDecimal;
import java.util.ArrayList;

public class UnaryLinearRegression2 {
	private double totalX;			//x的总和
	private double totalY;			//y的总和
	private double totalXX;			//x的二次方的总和
	private double totalXY;			//x乘y的总和
	private double totalYY;			//y的二次方的总和
	
	
	

	/** total of yi-y */
	private double totalDeltaY;
	/** total of sumDeltaY^2 */
	private double totalDeltaY2;//Delta:变动量

	/** 误差 */
	private double sse;
	private double sst;
	private double E;
	private String[] xy;

	private ArrayList listX;
	private ArrayList listY;

	private int XMin, XMax, YMin, YMax;

	/** line coefficient a0 */
	private float a0;
	/** line coefficient a1 */
	private float a1;

	/** number of data points */
	private int dataPointNumber;
	/** true if coefficients valid */
	private boolean coefsValid;//Coefficient:系数； （测定某种质量或变化过程的）率； 程度

	/**
	 * Constructor.
	 */
	public UnaryLinearRegression2() {
		XMax = 0;
		YMax = 0;
		dataPointNumber = 0;
		xy = new String[2];
		listX = new ArrayList();
		listY = new ArrayList();
	}

	/**
	 * Constructor.
	 * 
	 * @param data
	 *            the array of data points
	 */
	public UnaryLinearRegression2(UnaryDataPoint data[]) {
		dataPointNumber = 0;
		xy = new String[2];
		listX = new ArrayList();
		listY = new ArrayList();
		for (int i = 0; i < data.length; ++i) {
			addDataPoint(data[i]);
		}
	}

	/**
	 * Return the current number of data points.
	 * 
	 * @return the count
	 */
	public int getDataPointNumber() {
		return dataPointNumber;
	}

	/**
	 * Return the coefficient a0.
	 * 
	 * @return the value of a0
	 */
	public float getA0() {
		validateCoefficients();
		return a0;
	}

	/**
	 * Return the coefficient a1.
	 * 
	 * @return the value of a1
	 */
	public float getA1() {
		validateCoefficients();
		return a1;
	}

	/**
	 * Return the sum of the x values.
	 * 
	 * @return the sum
	 */
	public double getTotalX() {
		return totalX;
	}

	/**
	 * Return the sum of the y values.
	 * 
	 * @return the sum
	 */
	public double getTotalY() {
		return totalY;
	}

	/**
	 * Return the sum of the x*x values.
	 * 
	 * @return the sum
	 */
	public double getTotalXX() {
		return totalXX;
	}

	/**
	 * Return the sum of the x*y values.
	 * 
	 * @return the sum
	 */
	public double getTotalXY() {
		return totalXY;
	}

	public double getTotalYY() {
		return totalYY;
	}

	public int getXMin() {
		return XMin;
	}

	public int getXMax() {
		return XMax;
	}

	public int getYMin() {
		return YMin;
	}

	public int getYMax() {
		return YMax;
	}

	/**
	 * Add a new data point: Update the sums.
	 * 
	 * @param dataPoint
	 *            the new data point
	 */
	public void addDataPoint(UnaryDataPoint dataPoint) {
		totalX += dataPoint.getX();
		totalY += dataPoint.getY();
		totalXX += dataPoint.getX() * dataPoint.getX();
		totalXY += dataPoint.getX() * dataPoint.getY();
		totalYY += dataPoint.getY() * dataPoint.getY();

		if (dataPoint.getX() > XMax) {
			XMax = (int) dataPoint.getX();
		}
		if (dataPoint.getY() > YMax) {
			YMax = (int) dataPoint.getY();
		}

		// 把每个点的具体坐标存入ArrayList中，备用

		xy[0] = (int) dataPoint.getX() + "";
		xy[1] = (int) dataPoint.getY() + "";
		if (dataPoint.getX() != 0 && dataPoint.getY() != 0) {
			System.out.print(xy[0] + ",");
			System.out.println(xy[1]);

			try {
				// System.out.println("n:"+n);
				listX.add(dataPointNumber, xy[0]);
				listY.add(dataPointNumber, xy[1]);
			} catch (Exception e) {
				e.printStackTrace();
			}

			/*
			 * System.out.println("N:" + n);
			 * System.out.println("ArrayList listX:"+ listX.get(n));
			 * System.out.println("ArrayList listY:"+ listY.get(n));
			 */
		}
		++dataPointNumber;
		coefsValid = false;
	}

	/**
	 * Return the value of the regression line function at x. (Implementation of
	 * Evaluatable.)
	 * 
	 * @param x
	 *            the value of x
	 * @return the value of the function at x
	 */
	public float at(int x) {
		if (dataPointNumber < 2)
			return Float.NaN;

		validateCoefficients();
		return a0 + a1 * x;
	}

	public float at(float x) {
		if (dataPointNumber < 2)
			return Float.NaN;

		validateCoefficients();
		return a0 + a1 * x;
	}

	/**
	 * Reset.
	 */
	public void reset() {
		dataPointNumber = 0;
		totalX = totalY = totalXX = totalXY = 0;
		coefsValid = false;
	}

	/**
	 * Validate the coefficients. 计算方程系数 y=ax+b 中的a
	 */
	private void validateCoefficients() {
		if (coefsValid)
			return;

		if (dataPointNumber >= 2) {
			float xBar = (float) totalX / dataPointNumber;
			float yBar = (float) totalY / dataPointNumber;

			a1 = (float) ((dataPointNumber * totalXY - totalX * totalY) / (dataPointNumber * totalXX - totalX
					* totalX));
			a0 = (float) (yBar - a1 * xBar);
		} else {
			a0 = a1 = Float.NaN;
		}

		coefsValid = true;
	}

	/**
	 * 返回误差
	 */
	public double getR() {
		// 遍历这个list并计算分母
		for (int i = 0; i < dataPointNumber - 1; i++) {
			float Yi = (float) Integer.parseInt(listY.get(i).toString());
			float Y = at(Integer.parseInt(listX.get(i).toString()));
			float deltaY = Yi - Y;
			float deltaY2 = deltaY * deltaY;
			/*
			 * System.out.println("Yi:" + Yi); System.out.println("Y:" + Y);
			 * System.out.println("deltaY:" + deltaY);
			 * System.out.println("deltaY2:" + deltaY2);
			 */

			totalDeltaY2 += deltaY2;
			// System.out.println("sumDeltaY2:" + sumDeltaY2);

		}

		sst = totalYY - (totalY * totalY) / dataPointNumber;
		// System.out.println("sst:" + sst);
		E = 1 - totalDeltaY2 / sst;

		return round(E, 4);
	}
	public double round(double v, int scale) {
		if (scale < 0) {
			throw new IllegalArgumentException(
					"The scale must be a positive integer or zero");
		}
		BigDecimal b = new BigDecimal(Double.toString(v));
		BigDecimal one = new BigDecimal("1");
		return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
	}
}
